package com.ruoyi.system.service.impl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.Signature;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.common.utils.uuid.UUID;
import com.ruoyi.system.config.ServerUrlConfig;
import com.ruoyi.system.delay.DelayQueueManager;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.domain.dto.HospitalSubscribeCreateOrderDto;
import com.ruoyi.system.domain.event.OrderMessageEvent;
import com.ruoyi.system.domain.request.WeChatChargeBackRequest;
import com.ruoyi.system.domain.request.WeChatPayRequest;
import com.ruoyi.system.domain.vo.*;
import com.ruoyi.system.service.*;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAPublicKeyConfig;
import com.wechat.pay.java.core.http.*;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.core.util.PemUtil;
import com.wechat.pay.java.service.partnerpayments.app.model.PrepayResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import com.ruoyi.system.mapper.HospitalSubscribeOrderMapper;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Base64Utils;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import com.common.util.service.CommonService;
import javax.servlet.http.HttpServletRequest;

/**
 * 订单Service业务层处理
 *
 * @author ruoyi
 * @date 2025-04-30
 */
@Service
public class HospitalSubscribeOrderServiceImpl implements IHospitalSubscribeOrderService {
    @Autowired
    private HospitalSubscribeOrderMapper hospitalSubscribeOrderMapper;

    @Autowired
    private IHospitalSubscribeSetMealService iHospitalSubscribeSetMealService;

    @Autowired
    private IHospitalSubscribeProjectService iHospitalSubscribeProjectService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private DelayQueueManager delayQueueManager;

    @Autowired
    private ISysUserService iSysUserService;

    @Autowired
    private IHospitalSubscribeScheduleCapacityService iHospitalSubscribeScheduleCapacityService;

    @Autowired
    private IHospitalSubscribeRefundRecordService iHospitalSubscribeRefundRecordService;

    @Autowired
    private ApplicationEventPublisher publisher;

    @Autowired
    private CommonService commonService;

    @Autowired
    private ServerUrlConfig serverUrlConfig;

    @Autowired
    private IHospitalSubscribeScheduleDaysService iHospitalSubscribeScheduleDaysService;

    @Autowired
    private IHospitalSubscribeScheduleTemplateService iHospitalSubscribeScheduleTemplateService;

    /**
     * 查询订单
     *
     * @param id 订单主键
     * @return 订单
     */
    @Override
    public HospitalSubscribeOrder selectHospitalSubscribeOrderById(Long id) {
        return hospitalSubscribeOrderMapper.selectHospitalSubscribeOrderById(id);
    }

    /**
     * 查询订单列表
     *
     * @param hospitalSubscribeOrder 订单
     * @return 订单
     */
    @Override
    public List<HospitalSubscribeOrder> selectHospitalSubscribeOrderList(HospitalSubscribeOrder hospitalSubscribeOrder) {
        return hospitalSubscribeOrderMapper.selectHospitalSubscribeOrderList(hospitalSubscribeOrder);
    }

    /**
     * 新增订单
     *
     * @param hospitalSubscribeOrder 订单
     * @return 结果
     */
    @Override
    public int insertHospitalSubscribeOrder(HospitalSubscribeOrder hospitalSubscribeOrder) {
        hospitalSubscribeOrder.setCreateTime(DateUtils.getNowDate());
        return hospitalSubscribeOrderMapper.insertHospitalSubscribeOrder(hospitalSubscribeOrder);
    }

    /**
     * 修改订单
     *
     * @param hospitalSubscribeOrder 订单
     * @return 结果
     */
    @Override
    public int updateHospitalSubscribeOrder(HospitalSubscribeOrder hospitalSubscribeOrder) {
        hospitalSubscribeOrder.setUpdateTime(DateUtils.getNowDate());
        return hospitalSubscribeOrderMapper.updateHospitalSubscribeOrder(hospitalSubscribeOrder);
    }

    /**
     * 批量删除订单
     *
     * @param ids 需要删除的订单主键
     * @return 结果
     */
    @Override
    public int deleteHospitalSubscribeOrderByIds(Long[] ids) {
        return hospitalSubscribeOrderMapper.deleteHospitalSubscribeOrderByIds(ids);
    }

    /**
     * 删除订单信息
     *
     * @param id 订单主键
     * @return 结果
     */
    @Override
    public int deleteHospitalSubscribeOrderById(Long id) {
        return hospitalSubscribeOrderMapper.deleteHospitalSubscribeOrderById(id);
    }

    /**
     * 查询订单关联的所有信息
     *
     * @param hospitalSubscribeOrder
     * @return
     */
    @Override
    public List<HospitalSubscribeOrderVo> getOrderAllInfo(HospitalSubscribeOrder hospitalSubscribeOrder) {
        List<HospitalSubscribeOrderVo> orderAllInfo = hospitalSubscribeOrderMapper.getOrderAllInfo(hospitalSubscribeOrder);
        for (HospitalSubscribeOrderVo orderVo : orderAllInfo) {
            if (orderVo.getMeal() != null) {
                HospitalSubscribeSetMeal meal = orderVo.getMeal();
                String projectIds = meal.getProjectIds();
                Optional.ofNullable(iHospitalSubscribeProjectService.getHospitalSubscribeProjectByIds(Arrays.stream(projectIds.split(",")).collect(Collectors.toList()))).ifPresent(meal::setProjectList);
            }
        }
        return orderAllInfo;
    }

    /**
     * 创建订单
     *
     * @param dto
     * @return
     */
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public Map<String, String> createOrder(HospitalSubscribeCreateOrderDto dto) {
        HospitalSubscribeOrder order = new HospitalSubscribeOrder();
        Map<String, String> map = new HashMap<>(4);
        String orderNo = UUID.randomUUID().toString().replace("-", "");

        // 项目id或套餐id
        Long projectId = dto.getProjectId();
        order.setItemType(dto.getItemType());
        order.setProjectId(projectId);
        order.setNumber(dto.getNumber());
        // 套餐
        if (order.getItemType().equals(0)) {
            HospitalSubscribeSetMeal meal = iHospitalSubscribeSetMealService.selectHospitalSubscribeSetMealById(projectId);
            if (meal == null || meal.getIsShow().equals(1)) {
                throw new RuntimeException("下单的套餐不存在或已下架");
            }
            order.setMoney(new BigDecimal(dto.getNumber()).multiply(meal.getPrice()));
        }
        // 检查项目
        if (order.getItemType().equals(1)) {
            HospitalSubscribeProject project = iHospitalSubscribeProjectService.selectHospitalSubscribeProjectById(projectId);
            if (project == null || project.getIsShow().equals(1)) {
                throw new RuntimeException("下单的检查项目不存在或已下架");
            }
            order.setMoney(new BigDecimal(dto.getNumber()).multiply(project.getProjectPrice()));
        }


        order.setUserId(SecurityUtils.getUserId());
        order.setOrderNo(orderNo);
        this.insertHospitalSubscribeOrder(order);

        String uuid = UUID.randomUUID().toString().replace("-", "");
        redisCache.setCacheObject(CacheConstants.REPEAT_SUBMIT_KEY + orderNo, uuid, 15, TimeUnit.MINUTES);
        map.put("orderNo", orderNo);
        map.put("uuid", uuid);
        delayQueueManager.addOrder(orderNo, 15L);

        publisher.publishEvent(new OrderMessageEvent(this, orderNo, "订单号:" + orderNo + "还未支付,十五分钟后会自动关闭", order.getUserId()));
        return map;
    }

    /**
     * 根据订单号关闭订单
     *
     * @param orderNo
     */
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public void closeOrderByOrderNo(String orderNo) {
        HospitalSubscribeOrder order = new HospitalSubscribeOrder();
        order.setOrderNo(orderNo);
        order.setStatus(0);
        List<HospitalSubscribeOrder> orderList = hospitalSubscribeOrderMapper.selectHospitalSubscribeOrderList(order);
        for (HospitalSubscribeOrder subscribeOrder : orderList) {
            subscribeOrder.setStatus(5);
            this.updateHospitalSubscribeOrder(subscribeOrder);

            // 根据时间段id恢复余量
            Long scheduleCapacityId = subscribeOrder.getScheduleCapacityId();
            iHospitalSubscribeScheduleCapacityService.updateAvailableSlotsNumberById(scheduleCapacityId);
            publisher.publishEvent(new OrderMessageEvent(this, subscribeOrder.getOrderNo(), "订单号:" + subscribeOrder.getOrderNo() + "十五分钟未支付已经关闭", subscribeOrder.getUserId()));
        }
    }

    /**
     * 关闭超时订单
     */
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public void closeOrderList() {
        List<HospitalSubscribeOrder> orderList = hospitalSubscribeOrderMapper.closeOrderList();
        for (HospitalSubscribeOrder order : orderList) {
            order.setStatus(5);
            this.updateHospitalSubscribeOrder(order);

            // 根据时间段id恢复余量
            Long scheduleCapacityId = order.getScheduleCapacityId();
            iHospitalSubscribeScheduleCapacityService.updateAvailableSlotsNumberById(scheduleCapacityId);
            publisher.publishEvent(new OrderMessageEvent(this, order.getOrderNo(), "订单号:" + order.getOrderNo() + "十五分钟未支付已经关闭", order.getUserId()));
        }
    }

    /**
     * 订单支付
     *
     * @param map
     * @return
     */
    @Override
    public WeChatPayVo orderPay(Map<String, String> map) {
        String uuid = map.get("uuid");
        String orderNo = map.get("orderNo");

        // 订单信息
        HospitalSubscribeOrder order = new HospitalSubscribeOrder();
        order.setOrderNo(orderNo);
        order.setUserId(SecurityUtils.getUserId());
        List<HospitalSubscribeOrder> hospitalSubscribeOrders = hospitalSubscribeOrderMapper.selectHospitalSubscribeOrderList(order);
        if (CollectionUtils.isEmpty(hospitalSubscribeOrders)) {
            throw new RuntimeException("该订单不存在");
        }
        HospitalSubscribeOrder subscribeOrder = hospitalSubscribeOrders.get(0);
        if (subscribeOrder.getStatus() != 0) {
            throw new RuntimeException("该订单不是未支付状态");
        }

        Object cache = redisCache.getCacheObject(CacheConstants.REPEAT_SUBMIT_KEY + orderNo);
        if (cache == null || !cache.toString().equals(uuid)) {
            throw new RuntimeException("订单已过期,请重新体检订单");
        }
        // 支付金额 分
        BigDecimal payMoney = subscribeOrder.getMoney().multiply(new BigDecimal(100));

        WeChatPayRequest weChatPayRequest = new WeChatPayRequest();
        weChatPayRequest.setOutTradeNo(orderNo);
        weChatPayRequest.setDescription("医院体检预约");
        // 金额
        WeChatPayRequest.WeChatPayAmountRequest amountRequest = new WeChatPayRequest.WeChatPayAmountRequest();
        amountRequest.setTotal(payMoney.intValue());
        weChatPayRequest.setAmount(amountRequest);
        //支付人信息
        WeChatPayRequest.WeChatPayPayerRequest payPayerRequest = new WeChatPayRequest.WeChatPayPayerRequest();
        Long userId = SecurityUtils.getUserId();
        payPayerRequest.setOpenId(iSysUserService.selectUserById(userId).getOpenId());
        weChatPayRequest.setPayer(payPayerRequest);
        redisCache.deleteObject(CacheConstants.REPEAT_SUBMIT_KEY + orderNo);
        return this.weChatAppletPay(weChatPayRequest);
    }

    /**
     * 根据订单预约体检时间
     *
     * @param order
     * @return
     */
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public boolean makeAnAppointment(HospitalSubscribeOrder order) {
        // 订单信息
        HospitalSubscribeOrder orderInfo = this.selectHospitalSubscribeOrderById(order.getId());
        if (orderInfo == null) {
            throw new RuntimeException("该订单不存在");
        }
        orderInfo.setExaminerInfoId(order.getExaminerInfoId());
        orderInfo.setScheduleCapacityId(order.getScheduleCapacityId());

        HospitalSubscribeScheduleCapacity hospitalSubscribeScheduleCapacity = iHospitalSubscribeScheduleCapacityService.selectHospitalSubscribeScheduleCapacityById(orderInfo.getScheduleCapacityId());
        if (hospitalSubscribeScheduleCapacity != null) {
            Long daysId = hospitalSubscribeScheduleCapacity.getDaysId();
            HospitalSubscribeScheduleDays scheduleDays = iHospitalSubscribeScheduleDaysService.selectHospitalSubscribeScheduleDaysById(daysId);
            if (scheduleDays != null) {
                orderInfo.setDaysDate(scheduleDays.getDate());
            }
        }
        orderInfo.setStatus(4);
        this.updateHospitalSubscribeOrder(orderInfo);

        // 扣减时间段余量
        int i = iHospitalSubscribeScheduleCapacityService.reduceNumberByScheduleCapacityId(order.getScheduleCapacityId());
        if (i == 0) {
            throw new RuntimeException("该时间段已预约完");
        }

        publisher.publishEvent(new OrderMessageEvent(this, orderInfo.getOrderNo(), "订单号:" + orderInfo.getOrderNo() + "已预约成功", orderInfo.getUserId()));
        return true;
    }

    /**
     * 根据订单号查询订单信息
     *
     * @param orderNo
     * @return
     */
    @Override
    public HospitalSubscribeOrder getOrderInfoByOrderNo(String orderNo) {
        return hospitalSubscribeOrderMapper.getOrderInfoByOrderNo(orderNo);
    }

    /**
     * 支付成功回调
     *
     * @param request
     * @return
     */
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public HashMap<String, String> paySuccessCallback(HttpServletRequest request) {
        HashMap<String, String> map = new HashMap<>(4);
        try {
            WeChatPayCallbackVo weChatPayCallbackVo = this.weChatAppletPayNotify(request);
            if ("SUCCESS".equals(weChatPayCallbackVo.getFlag())) {
                String transactionId = weChatPayCallbackVo.getTransactionId();
                String outTradeNo = weChatPayCallbackVo.getOutTradeNo();
                HospitalSubscribeOrder order = this.getOrderInfoByOrderNo(outTradeNo);
                if (order != null) {
                    order.setWeChatOrderNo(transactionId);
                    order.setStatus(1);
                    order.setPaymentTime(new Date());
                    this.updateHospitalSubscribeOrder(order);

                    publisher.publishEvent(new OrderMessageEvent(this, outTradeNo, "订单号:" + outTradeNo + "已支付成功", order.getUserId()));
                }
                map.put("code", "200");
                return map;
            }
        } catch (Exception e) {
            map.put("code", "500");
            map.put("FAIL", "失败");
            return map;
        }
        map.put("code", "500");
        map.put("FAIL", "失败");
        return map;
    }

    /**
     * 根据订单项修改预约体检时间
     *
     * @param order
     * @return
     */
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public boolean updateMakeAnAppointment(HospitalSubscribeOrder order) {
        // 订单项信息
        HospitalSubscribeOrder orderInfo = this.selectHospitalSubscribeOrderById(order.getId());
        if (orderInfo == null) {
            throw new RuntimeException("该订单项不存在");
        }

        if (orderInfo.getScheduleCapacityId().equals(order.getScheduleCapacityId())) {
            throw new RuntimeException("该时间段你已经预约成功了,无需重复预约");
        }

        // 根据时间段id恢复余量
        Long scheduleCapacityId = order.getScheduleCapacityId();
        iHospitalSubscribeScheduleCapacityService.updateAvailableSlotsNumberById(scheduleCapacityId);

        // 扣减新时间段余量
        int i = iHospitalSubscribeScheduleCapacityService.reduceNumberByScheduleCapacityId(order.getScheduleCapacityId());
        if (i == 0) {
            throw new RuntimeException("该时间段已预约完");
        }
        HospitalSubscribeScheduleCapacity hospitalSubscribeScheduleCapacity = iHospitalSubscribeScheduleCapacityService.selectHospitalSubscribeScheduleCapacityById(orderInfo.getScheduleCapacityId());
        if (hospitalSubscribeScheduleCapacity != null) {
            Long daysId = hospitalSubscribeScheduleCapacity.getDaysId();
            HospitalSubscribeScheduleDays scheduleDays = iHospitalSubscribeScheduleDaysService.selectHospitalSubscribeScheduleDaysById(daysId);
            if (scheduleDays != null) {
                orderInfo.setDaysDate(scheduleDays.getDate());
            }
        }
        this.updateHospitalSubscribeOrder(orderInfo);

        publisher.publishEvent(new OrderMessageEvent(this, orderInfo.getOrderNo(), "订单号:" + orderInfo.getOrderNo() + "已预约成功", orderInfo.getUserId()));
        return true;
    }

    /**
     * 退款成功回调
     *
     * @param request
     * @return
     */
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public HashMap<String, String> refundSuccessCallback(HttpServletRequest request) {
        HashMap<String, String> map = new HashMap<>(4);
        try {
            WeChatRefundCallbackVo weChatRefundCallbackVo = this.weChatAppletChargebackNotify(request);
            if ("SUCCESS".equals(weChatRefundCallbackVo.getFlag())) {
                // 订单号
                String outTradeNo = weChatRefundCallbackVo.getOutTradeNo();
                // 退单单号
                String outRefundNo = weChatRefundCallbackVo.getOutRefundNo();
                // 微信退款单号
                String refundId = weChatRefundCallbackVo.getRefundId();

                HospitalSubscribeOrder order = this.getOrderInfoByOrderNo(outTradeNo);
                if (order != null) {
                    order.setWeChatRefundOrderNo(refundId);
                    order.setStatus(3);
                    order.setWeChatRefundOrderNo(outRefundNo);
                    order.setRefundTime(new Date());
                    this.updateHospitalSubscribeOrder(order);

                    // 退款记录
                    HospitalSubscribeRefundRecord refundRecord = new HospitalSubscribeRefundRecord();
                    refundRecord.setWeChatRefundOrderNo(refundId);
                    refundRecord.setOrderId(order.getId());
                    refundRecord.setRefundQuantity(order.getNumber());
                    refundRecord.setRefundAmount(order.getMoney());
                    refundRecord.setOutRefundNo(outRefundNo);
                    iHospitalSubscribeRefundRecordService.insertHospitalSubscribeRefundRecord(refundRecord);

                    publisher.publishEvent(new OrderMessageEvent(this, outTradeNo, "订单号:" + outTradeNo + "已退款成功", order.getUserId()));

                }
                map.put("code", "200");
                return map;
            }
        } catch (Exception e) {
            map.put("code", "500");
            map.put("FAIL", "失败");
            return map;
        }
        map.put("code", "500");
        map.put("FAIL", "失败");
        return map;
    }


    /**
     * 完成订单
     *
     * @param orderId
     * @return
     */
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public boolean completeOrder(Long orderId) {
        HospitalSubscribeOrder order = this.selectHospitalSubscribeOrderById(orderId);
        order.setCodeUrl(this.getCodeUrl("www.whjxzfjwsfwzx.cn/prod-api/applet/results/selectList?orderNo=" + order.getOrderNo()));
        order.setStatus(2);
        order.setCompleteTime(new Date());
        this.updateHospitalSubscribeOrder(order);

        publisher.publishEvent(new OrderMessageEvent(this, order.getOrderNo(), "订单号:" + order.getOrderNo() + "已完成", order.getUserId()));
        return true;
    }

    /**
     * 订单申请退款
     *
     * @param orderId
     * @return
     */
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public boolean refundOrder(Long orderId) {
        String outRefundNo = System.currentTimeMillis() / 1000 + "";

        HospitalSubscribeOrder order = this.selectHospitalSubscribeOrderById(orderId);
        if (order == null) {
            throw new RuntimeException("该订单不存在");
        }

        order.setOutRefundNo(outRefundNo);
        order.setStatus(6);
        this.updateHospitalSubscribeOrder(order);

        // 微信退款参数
        WeChatChargeBackRequest request = new WeChatChargeBackRequest();
        request.setTransactionId(order.getWeChatOrderNo());
        request.setOutRefundNo(outRefundNo);
        // 退款金额
        WeChatChargeBackRequest.WeChatChargeBackAmountRequest amountRequest = new WeChatChargeBackRequest.WeChatChargeBackAmountRequest();
        amountRequest.setRefund(order.getMoney().multiply(new BigDecimal(100)).intValue());
        amountRequest.setTotal(order.getMoney().multiply(new BigDecimal(100)).intValue());
        request.setAmount(amountRequest);
        this.weChatAppletChargeback(request);

        publisher.publishEvent(new OrderMessageEvent(this, order.getOrderNo(), "订单号:" + order.getOrderNo() + "已申请退款", order.getUserId()));
        return true;
    }

    /**
     * 已预约待上传结果
     */
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public void completeOrderList() {
        HospitalSubscribeOrder order = new HospitalSubscribeOrder();
        order.setStatus(4);
        List<HospitalSubscribeOrder> hospitalSubscribeOrders = hospitalSubscribeOrderMapper.selectHospitalSubscribeOrderList(order);
        if (!CollectionUtils.isEmpty(hospitalSubscribeOrders)) {
            for (HospitalSubscribeOrder hospitalSubscribeOrder : hospitalSubscribeOrders) {
                Long scheduleCapacityId = hospitalSubscribeOrder.getScheduleCapacityId();
                HospitalSubscribeScheduleCapacity hospitalSubscribeScheduleCapacity = iHospitalSubscribeScheduleCapacityService.selectHospitalSubscribeScheduleCapacityById(scheduleCapacityId);
                if (hospitalSubscribeScheduleCapacity != null) {
                    Long templateId = hospitalSubscribeScheduleCapacity.getTemplateId();
                    HospitalSubscribeScheduleTemplate hospitalSubscribeScheduleTemplate = iHospitalSubscribeScheduleTemplateService.selectHospitalSubscribeScheduleTemplateById(templateId);
                    if (hospitalSubscribeOrder.getDaysDate() != null) {
                        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
                        String format = simpleDateFormat.format(hospitalSubscribeOrder.getDaysDate());
                        String date = format + " " + hospitalSubscribeScheduleTemplate.getEndTime();
                        hospitalSubscribeOrderMapper.closeOrderById(hospitalSubscribeOrder.getId(), date);
                    }
                }
            }
        }
    }

    @Override
    public String getCodeUrl(String url) {
        byte[] bytes = commonService.generateQrCodeBytes(url, 200, 200, 0);
        MultipartFile multipartFile = commonService.convertBytesToMultipartFile(bytes, java.util.UUID.randomUUID().toString().replace("-", ""));
        // 上传文件路径
        String filePath = RuoYiConfig.getUploadPath();
        // 上传并返回新文件名称
        String fileName = null;
        try {
            fileName = FileUploadUtils.upload(filePath, multipartFile);
        } catch (IOException e) {
            throw new RuntimeException("上传文件失败");
        }
        return serverUrlConfig.getUrl()+"/prod-api" + fileName;
    }

    public WeChatPayVo weChatAppletPay(WeChatPayRequest request) {
        this.initWxPayClient();
        WeChatPayVo vo = new WeChatPayVo();
        request.setAppid("wx159bb0413d5de717");
        request.setMchId("1716989516");
        request.setNotifyUrl("https://www.whjxzfjwsfwzx.cn/prod-api/admin/order/paySuccessCallback");

        // 创建HTTP头信息，设置接收和内容类型为JSON
        HttpHeaders headers = new HttpHeaders();
        headers.addHeader(Constant.ACCEPT, MediaType.APPLICATION_JSON.getValue());
        headers.addHeader(Constant.CONTENT_TYPE, MediaType.APPLICATION_JSON.getValue());
        headers.addHeader(Constant.WECHAT_PAY_SERIAL, "PUB_KEY_ID_0117169895162025051500351956001401");
        headers.addHeader(Constant.VERSION, "1.1");
        // 构建HTTP请求，设置请求方法为POST，URL为微信支付API接口地址
        HttpRequest httpRequest =
                null;
        try {
            httpRequest = new HttpRequest.Builder()
                    .httpMethod(HttpMethod.POST)
                    .url("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi")
                    .headers(headers)
                    // 设置请求体为createRequestBody方法返回的内容
                    .body(this.createRequestBody(request))
                    .build();
        } catch (JsonProcessingException e) {
            throw new RuntimeException("下单失败");
        }

        // 执行HTTP请求，并将响应体转换为PrepayResponse类对象
        HttpResponse<PrepayResponse> httpResponse = httpClient.execute(httpRequest, PrepayResponse.class);

        // 获取响应体
        ResponseBody responseBody = httpResponse.getBody();

        // 将响应体转换为JSON对象并返回
        String jsonString = JSON.toJSONString(responseBody);
        JSONObject jsonObject = JSONObject.parseObject(jsonString);

        String prepayId = JSONObject.parseObject(jsonObject.getString("body")).getString("prepay_id");
        if (StringUtils.isBlank(prepayId)) {
            throw new RuntimeException("创建微信支付订单失败");
        }
        // 生成签名
        Long timestamp = System.currentTimeMillis() / 1000;

        // 随机字符串
        String nonceStr = UUID.randomUUID().toString().replaceAll("-", "");

        // 生成带签名支付信息
        vo.setAppId("wx159bb0413d5de717");
        vo.setTimeStamp(String.valueOf(timestamp));
        vo.setNonceStr(nonceStr);
        vo.setPackageValue("prepay_id="+ prepayId);
        try {
            String signatureStr = Stream.of("wx159bb0413d5de717", String.valueOf(timestamp), nonceStr, vo.getPackageValue())
                    .collect(Collectors.joining("\n", "", "\n"));
            String sign = this.getSign(signatureStr);
            vo.setPaySign(sign);
            return vo;
        } catch (Exception e) {
            throw new RuntimeException("支付失败");
        }
    }

    public static HttpClient httpClient;

    private void initWxPayClient() {
        // 创建RSAPublicKeyConfig配置对象
        Config config =
                new RSAPublicKeyConfig.Builder()
                        // 设置商户ID
                        .merchantId("1716989516")
                        // 从指定路径加载私钥
                        .privateKey(loadPrivateKeyFromPem("/wxPay/apiclient_key.pem"))
                        // 从指定路径加载公钥
                        .publicKey(loadPublicKeyFromPem("/wxPay/pub_key.pem"))
                        // 设置公钥ID
                        .publicKeyId("PUB_KEY_ID_0117169895162025051500351956001401")
                        // 设置商户API证书的证书序列号
                        .merchantSerialNumber("35E092F8A70EEC811E3A5EA11D97C43D85781BC0")
                        // 设置APIv3密钥
                        .apiV3Key("1627210206184d068a9ba5e19dcedaa3")
                        // 构建配置对象
                        .build();

        // 创建HttpClient实例，并应用配置
        httpClient =
                new DefaultHttpClientBuilder()
                        // 应用之前创建的配置
                        .config(config)
                        // 设置连接超时时间为500毫秒
                        .connectTimeoutMs(500)
                        // 构建HttpClient实例
                        .build();


    }

    private RequestBody createRequestBody(Object request) throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        return new JsonRequestBody.Builder().body(mapper.writeValueAsString(request)).build();
    }

    private String getSign(String signatureStr) throws Exception {
        PrivateKey merchantPrivateKey = PemUtil.loadPrivateKeyFromString(loadPrivateKeyFromPem("/wxPay/apiclient_key.pem"));
        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(merchantPrivateKey);
        sign.update(signatureStr.getBytes(StandardCharsets.UTF_8));
        return Base64Utils.encodeToString(sign.sign());
    }

    public WeChatChargeBackVo weChatAppletChargeback(WeChatChargeBackRequest request) {
        this.initWxPayClient();
        try {
            request.setNotifyUrl("https://www.whjxzfjwsfwzx.cn/prod-api/admin/order/refundSuccessCallback");

            HttpHeaders headers = new HttpHeaders();
            headers.addHeader(Constant.ACCEPT, MediaType.APPLICATION_JSON.getValue());
            headers.addHeader(Constant.CONTENT_TYPE, MediaType.APPLICATION_JSON.getValue());
            headers.addHeader("Wechatpay-Serial", "PUB_KEY_ID_0117169895162025051500351956001401");

            HttpRequest httpRequest =
                    new HttpRequest.Builder()
                            .httpMethod(HttpMethod.POST)
                            .url("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds")
                            .headers(headers)
                            .body(this.createRequestBody(request))
                            .build();

            HttpResponse<com.wechat.pay.java.service.partnerpayments.nativepay.model.PrepayResponse> httpResponse = httpClient.execute(httpRequest, com.wechat.pay.java.service.partnerpayments.nativepay.model.PrepayResponse.class);

            ResponseBody responseBody = httpResponse.getBody();
            WeChatChargeBackVo chargeBackVo = JSON.parseObject(JSONObject.parseObject(JSON.toJSONString(responseBody)).getString("body"), WeChatChargeBackVo.class);
            if (StringUtils.isBlank(chargeBackVo.getRefundId())) {
                throw new RuntimeException("退单返回数据为空");
            }

            return chargeBackVo;
        }

        catch (Exception e) {
            throw new RuntimeException("退单返回数据为空");
        }
    }

    public WeChatRefundCallbackVo weChatAppletChargebackNotify(HttpServletRequest request) {
        try {
            RequestParam requestParam = buildRequestParam(request);
            WeChatRefundCallbackVo callbackVo = buildNotificationConfig().parse(requestParam, WeChatRefundCallbackVo.class);
            String refundStatus = callbackVo.getRefundStatus();
            // 退款成功
            if ("SUCCESS".equalsIgnoreCase(refundStatus)) {
                callbackVo.setFlag("SUCCESS");
                return callbackVo;
            }
            callbackVo.setFlag("FLAG");
            return callbackVo;
        } catch (Exception e) {
            throw new RuntimeException("微信支付回调失败");
        }
    }

    private RequestParam buildRequestParam(HttpServletRequest request) throws IOException {
        BufferedReader br = request.getReader();
        String str;
        StringBuilder sb = new StringBuilder();
        while ((str = br.readLine()) != null) {
            sb.append(str);
        }
        return new RequestParam.Builder()
                .serialNumber(request.getHeader("Wechatpay-Serial"))
                .nonce(request.getHeader("Wechatpay-Nonce"))
                .signature(request.getHeader("Wechatpay-Signature"))
                .timestamp(request.getHeader("Wechatpay-Timestamp"))
                .body(sb.toString())
                .build();
    }

    private NotificationParser buildNotificationConfig() {
        NotificationConfig config =

                new RSAPublicKeyConfig.Builder()
                        .merchantId("1716989516")
                        .privateKey(loadPrivateKeyFromPem("/wxPay/apiclient_key.pem"))
                        .publicKey(loadPublicKeyFromPem("/wxPay/pub_key.pem"))
                        .publicKeyId("PUB_KEY_ID_0117169895162025051500351956001401")
                        .merchantSerialNumber("35E092F8A70EEC811E3A5EA11D97C43D85781BC0")
                        .apiV3Key("1627210206184d068a9ba5e19dcedaa3")
                        .build();
        return new NotificationParser(config);
    }

    public WeChatPayCallbackVo weChatAppletPayNotify(HttpServletRequest request) {
        try {
            RequestParam requestParam = buildRequestParam(request);
            WeChatPayCallbackVo callbackVo = buildNotificationConfig().parse(requestParam, WeChatPayCallbackVo.class);
            String tradeState = callbackVo.getTradeState();
            if ("SUCCESS".equalsIgnoreCase(tradeState)) {
                callbackVo.setFlag("SUCCESS");
                return callbackVo;
            }
            callbackVo.setFlag("FLAG");
            return callbackVo;
        } catch (IOException e) {
            throw new RuntimeException("微信支付回调失败");
        }
    }


    private String loadPrivateKeyFromPem(String privateKey) {
        InputStream privateStream = getClass().getResourceAsStream(privateKey);
        if (privateStream == null) {
            throw new RuntimeException("加载私钥失败");
        }
        // 读取私钥文件内容
        StringBuilder keyContentBuilder = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(privateStream, StandardCharsets.UTF_8))) {
            String line;
            while ((line = reader.readLine()) != null) {
                keyContentBuilder.append(line).append("\n");
            }
        } catch (Exception e) {
            throw new RuntimeException("加载私钥失败");
        }

        return keyContentBuilder.toString();

    }


    private String loadPublicKeyFromPem(String publicKey) {
        InputStream privateStream = getClass().getResourceAsStream(publicKey);
        if (privateStream == null) {
            throw new RuntimeException("加载公钥失败");
        }
        // 读取私钥文件内容
        StringBuilder keyContentBuilder = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(privateStream, StandardCharsets.UTF_8))) {
            String line;
            while ((line = reader.readLine()) != null) {
                keyContentBuilder.append(line).append("\n");
            }
        } catch (Exception e) {
            throw new RuntimeException("加载公钥失败");
        }

        return keyContentBuilder.toString();

    }
}
